/*
 * HttpResponse.cpp
 *
 *  Created on: Jul 11, 2024
 *      Author: root
 */

#include <src/bsp/http/HttpResponse.h>
#define TAG "http_response"
#include "all_header.h"
namespace bsp {

const std::unordered_map<std::string, std::string> HttpResponse::SUFFIX_TYPE = {
		{ ".html", "text/html" }, { ".xml", "text/xml" }, { ".xhtml",
				"application/xhtml+xml" }, { ".txt", "text/plain" }, { ".rtf",
				"application/rtf" }, { ".pdf", "application/pdf" }, { ".word",
				"application/nsword" }, { ".png", "image/png" }, { ".gif",
				"image/gif" }, { ".jpg", "image/jpeg" },
		{ ".jpeg", "image/jpeg" }, { ".au", "audio/basic" }, { ".mpeg",
				"video/mpeg" }, { ".mpg", "video/mpeg" }, { ".avi",
				"video/x-msvideo" }, { ".gz", "application/x-gzip" }, { ".tar",
				"application/x-tar" }, { ".css", "text/css " }, { ".js",
				"text/javascript " },{".ico","image/ico"},{".mp4","vide/mp4"} };

const std::unordered_map<int, std::string> HttpResponse::CODE_STATUS = { { 200,
		"OK" }, { 400, "Bad Request" }, { 403, "Forbidden" },
		{ 404, "Not Found" }, };

HttpResponse::HttpResponse() :
		keep_alive { false }, code_num { 0 }, file_fd { -1 }, file_size { 0 }, map_addr {
				nullptr } {
	// TODO Auto-generated constructor stub

}

HttpResponse::~HttpResponse() {
	// TODO Auto-generated destructor stub
	close();
}

void HttpResponse::close() {
	if (file_fd > -1) {
		::close(file_fd);
		file_fd = -1;
	}

	if (map_addr) {
		munmap(map_addr, file_size);
		map_addr = nullptr;
	}
}

int HttpResponse::open() {
	int ret = -1;
	code_num = 404; ///< must 404
	suffix = "";
	file_size = 0;
	file_fd = -1;

	do {
		if (file.empty() || dir.empty()) {
			ret = -1;
			break;
		}

		auto pos = file.find_last_of('.');
		if (pos == std::string::npos || pos == 0) {
			ret = -2;
			break;
		}

		suffix = file.substr(pos);
		if (SUFFIX_TYPE.count(suffix) == 0) {
			ret = -3;
			break;
		}

		struct stat st;
		MEM_ZERO(st);
		auto fullname = dir + "/" + file;
		if (stat(fullname.c_str(), &st) == 0) {

		} else if (errno == EACCES) {
			code_num = 403;
			ret = -4;
			break;
		} else {
			code_num = 404;
			ret = -5;
			break;
		}

		if (st.st_mode & S_IFDIR) {
			code_num = 403;
			ret = -6;
			break;
		}

		file_fd = ::open(fullname.c_str(), O_RDONLY);
		ASSERT(file_fd > -1, "");

		file_size = st.st_size;
		if (file_size > 0) {
			map_addr = (char*) mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE,
					file_fd, 0);
			ASSERT(map_addr, "");
		}
		code_num = 200;
		ret = 0;
	} while (0);
	return ret;
}

std::string HttpResponse::getHeader() {
	std::string ret = [code=code_num] {
		char buf[40];
		snprintf(buf, sizeof(buf), "HTTP/1.1 %d %s\r\n", code,
				CODE_STATUS.find(code)->second.c_str());
		std::string s = buf;
		return s;
	}.operator ()();

// header
	ret += [alive=keep_alive, suffix=suffix, file_size = file_size] {
		char buf[50];
		std::string ret;
		if (alive) {
			ret = "Connection: keep-alive\r\nKeep-Alive: max=6, timeout=120\r\n";
		} else {
			ret = "Connection: close\r\n";
		}

		if (SUFFIX_TYPE.count(suffix) == 1) {
			snprintf(buf, sizeof(buf), "Content-Type: %s; charset=utf-8\r\n",
					SUFFIX_TYPE.find(suffix)->second.c_str());
			ret.append(buf);

			snprintf(buf, sizeof(buf), "Content-Length: %d\r\n\r\n", file_size);
			ret.append(buf);
		}
		return ret;
	}.operator ()();

	return ret;
}

void HttpResponse::test1() {
	HttpResponse response;

	response.setFile(".", "/log.txt");
	response.setKeepAlive(true);
	int ret = response.open();
	if (ret == 0) {
		LOG_D(NL "%s" NL, response.getHeader().c_str());
		LOG_D("map addr %p" NL, response.getMapAddr());
		response.close();
	} else {
		LOG_D("open file failed %d" NL, ret);
	}
}

} /* namespace bsp */
